<?php
/*
	aspell interface that works without PHP's library.
*/
class aspell {
	private $aspell_prog = 'C:/Progra~1/Aspell/bin/aspell.exe';		//	Use setAspell_prog() to point to your aspell executable
	private $lang = 'en_US';
	private $aspell_opts;
	private $maxWords = 10;			//	How many words to return in each suggestion
	private $ignoreTags = false;	//	Ignore tags for spell checking
	private $tempfiledir = "./";
	private $result = array();

	function __construct() {
		$this->aspell_opts = "-a --lang=" . $this->lang . " --encoding=utf-8";
	}
	
	public function setMaxWords( $value ) {
		$this->maxWords = $value;
	}

	public function setIgnoreTags( $value ) {
		$this->ignoreTags = $value;
	}

	public function setAspell_prog( $value ) {
		$this->aspell_prog = $value;
	}

	# handle error.
	private function error( $error ) {
		print "apell error: " . $error;
	}

	/*	This return an array with words and suggested indexes as such:
		
		fieldName1: {
			'misspeltword1': [ list, of, suggested, words ],
			'misspeltword2': [ list, of, other, suggested, words ]
		},
		fieldName2: {... etc...
		
		$text can be either a string, or a dictionary with fieldnames as keys.		
	*/
	public function check( $text ) {
		//	Strip out tags before spell check...
		if( $this->ignoreTags )$text = strip_tags( $text );	
		
		if( ! is_array( $text ) )$text = array( "result" => $text );	//	We could handle multiple requests at once, in the future here...
		$fieldNames = array_keys( $text );
		$finalResult = array();
		$error = "";
		
		//	open temp file, add the submitted text.
		$tempfile = tempnam( $this->tempfiledir, 'aspell_data_' );
		$fp = fopen( $tempfile, 'w' );
		if( $fp ) {
			//	Loop on text entries, and write to file
			foreach( $text as $k => $v ) {
				fwrite ( $fp, "%\n^A\n!\n" );	//	exit terse mode, set the seperator, start terse mode.
				$lines = explode( "\n", urldecode( $v ) );
				foreach( $lines as $key=>$value )fwrite( $fp, "^" . $value . "\n" );	//	We use a carat on each line to escape aspell commands
			}
			fclose( $fp );
			
			//	Run aspell, redirecting STDERR to STDOUT
			$cmd = $this->aspell_prog . " " . $this->aspell_opts . " < " . $tempfile . " 2>&1";
			if( $aspellResult = shell_exec( $cmd ) ) {
				$lineResult = explode( "\n", $aspellResult );
				//	parse each line of aspell result
				$index = -1;
				foreach( $lineResult as $key=> $val ) {
					$result = array();
					$char = substr( $val, 0, 1 );
					if( $char == '#' or $char == '&' ) {		// '#' - not in dictionary, no suggestions, '&' - not in dictionary, has suggestions
						$line = explode( " ", $val, 5 );
						$result = array();
						$words = ( isset( $line[4] ) )? $words = explode( ", ", $line[4] ): array();
						$wordCount = 0;
						foreach( $words as $key => $val ) {
							if( $val and $wordCount < $this->maxWords )$result[] = $val;
							$wordCount += 1;
						}
					} elseif( $char == '*' ) {					//	'*' - delimiter for input text
						$index += 1;
					} elseif( $char != '@' && $char != "" ) {	//	'@' - version info, otherwise we have an error.
						$error .= $val;
					}
					if( sizeof( $result ) > 0 ) {				//	Add the result
						$finalResult[$fieldNames[$index]][$line[1]] = $result;
					}
				}
				
				if( $error )$this->error( $error . " command: '" . $cmd . "'" );
			} else $this->error( "Could not execute aspell, command: '" . $cmd . "'" );
		} else $this->error( "Could not open tempfile '" . $tempfile . "'" );
		
		$this->result = $finalResult;
		
		# close temp file, delete file
		unlink( $tempfile );
		
		return $this->result;
	}
	
	public function json() {
		return $this->arrayToJSON( $this->result );
	}
	
	//  This JSON conversion method is a poor hack job, though it adequately demonstrates how things should work.  
	private function arrayToJSON( $arr ) {
		$jsonArray = array();
		
		//	bad and good characters, for both key and values
		$badChars = array( 	"\n", 	"\r", 	"\"" );
		$goodChars = array(	"\\n",	"\\r",	"\\\"" );

		//	Check if this is a "numeric key" array (ie: a list).
		$isNumeric = true;
		foreach( $arr as $k => $v )if( ! is_int($k) )$isNumeric = false;
		
		foreach( $arr as $k => $v ) {
			//	Note: addSlashed will quote ', which is NOT what we want.
			$myKey = str_replace( 	$badChars, $goodChars, $k );
			$myValue = str_replace(	$badChars, $goodChars, $v );
			if( is_array( $v ) )$jsonArray[$myKey] = $this->arrayToJSON( $v );
			else $jsonArray[$myKey] = '"' . $myValue . '"';
		}
		
		if( $isNumeric ) {
			foreach( $jsonArray as $k => $v )$jsonArray[$k] = $v;
			return "[" . join( ", ", $jsonArray ) . "]";
		} else {
			foreach( $jsonArray as $k => $v )$jsonArray[$k] = $k . ": " . $v;
			return "{" . join( ", ", $jsonArray ) . "}";
		}
	}
	
}
?>